import http from "~/utils/httpRequest"
import qs from 'qs'
import allConfig from './config'


function handlePath(url: string, params) {
    // '?id&name' 这种形式的路由参数
    if (url.includes('?')) {
        const before = url.split('?')[0]
        const late = url.split('?')[1]
        const slots = late.split('&')
        let padUrl = ''
        if (typeof params === 'object') {
            padUrl = slots.map(key => {
                let re = `${key}=${params[key] || ''}`
                params[key] = undefined
                return re
            }).join('&')
        }
        if (padUrl) {
            return before + '?' + padUrl
        }
        return before
    }
    // '/:id/:num' 这种形式的路由参数
    if (url.includes(':')) {
        const urls = url.split('/')
        let handleUrl = urls.filter(ne => ne && !ne.startsWith(':')).join('/')
        handleUrl = handleUrl ? ('/' + handleUrl) : handleUrl

        // 如果是简单数据类型
        const isSimple = ['string', 'number'].includes(typeof params)

        //处理完毕的地址片段集合
        const handles = urls.filter(r => {
            const tar = r.replace(':', '')
            if (isSimple) {
                return r.startsWith(':')
            }
            return r.startsWith(':') && (params[tar] || params[tar] === '')
        }).map(iurl => {
            const tar = iurl.replace(':', '')
            if (isSimple) {
                return params
            } else {
                let res = params[tar]
                params[tar] = undefined
                return res
            }
        })
        // 如果是简单数据类型参数，只需要匹配第一个动态路由参数
        if (isSimple) {
            return [handleUrl, handles[0]].join('/')
        }

        // 如果是对象数据类型参数，匹配所有动态路由参数
        return [handleUrl, ...handles].join('/')
    }
    return url
}

export function Model(url: string, usePrefix: boolean = true) {
    return function (target) {
        target.prototype._baseUrl = url
        target.prototype.usePrefix = usePrefix
    }
}

export function Http(url: string, opts: { method: "POST" | "GET" | "PUT" | "DELETE", headers?: any }, flag?: boolean) {
    return function (target, _prop: string, descriptor: PropertyDescriptor) {
        const method = descriptor.value
        descriptor.value = async function () {
            let params = arguments[0]
            const isSimple = ['string', 'number'].includes(typeof params)
            const handleUrl = handlePath(url, params)
            if (isSimple) {
                params = {}
            }
            const { data } = await http({
                url: target.usePrefix ? http.adornUrl((target._baseUrl || '') + handleUrl) : ((target._baseUrl || '') + handleUrl),
                [opts.method === "GET" ? "params" : "data"]: http["adorn" + (opts.method === "GET" ? "Params" : "Data")](params, flag),
                ...opts
            })
            return method(data)
        }
    }
}

export function Get(url: string, flag?: boolean, headers?: any) {
    return function (target, _prop: string, descriptor: PropertyDescriptor) {
        const method = descriptor.value
        descriptor.value = async function () {
            let params = arguments[0]
            const isSimple = ['string', 'number'].includes(typeof params)
            const handleUrl = handlePath(url, params)
            if (isSimple) {
                params = {}
            }
            const { data } = await http({
                url: target.usePrefix ? http.adornUrl((target._baseUrl || '') + handleUrl) : ((target._baseUrl || '') + handleUrl),
                method: 'GET',
                params: http.adornParams(params, flag),
                headers
            })
            return method(data)
        }
    }
}

export function QsGet(url: string, flag?: boolean, headers?: any) {
    return function (target, _prop: string, descriptor: PropertyDescriptor) {
        const method = descriptor.value
        descriptor.value = async function () {
            let params = arguments[0]
            const isSimple = ['string', 'number'].includes(typeof params)
            const handleUrl = handlePath(url, params)
            if (isSimple) {
                params = {}
            }
            const preUrl = target.usePrefix ? http.adornUrl((target._baseUrl || '') + handleUrl) : ((target._baseUrl || '') + handleUrl)
            const { data } = await http({
                url: preUrl + (flag ? '?t=' + new Date().getTime() + '&' : '?') + qs.stringify(params),
                method: 'GET',
                headers
            })
            return method(data)
        }
    }
}

export function Post(url: string = '', flag?: boolean, headers?: any) {
    return function (target, _prop: string, descriptor: PropertyDescriptor) {
        const method = descriptor.value
        descriptor.value = async function () {
            let params = arguments[0]
            const isSimple = ['string', 'number'].includes(typeof params)
            const handleUrl = handlePath(url, params)
            if (isSimple) {
                params = {}
            }
            const { data } = await http({
                url: target.usePrefix ? http.adornUrl((target._baseUrl || '') + handleUrl) : ((target._baseUrl || '') + handleUrl),
                method: 'POST',
                data: http.adornData(params, flag),
                headers
            })
            return method(data)
        }
    }
}

export function PurePost(url: string = '', headers?: any) {
    return function (target, _prop: string, descriptor: PropertyDescriptor) {
        const method = descriptor.value
        descriptor.value = async function () {
            let params = arguments[0]
            const isSimple = ['string', 'number'].includes(typeof params)
            const handleUrl = handlePath(url, params)
            if (isSimple) {
                params = {}
            }
            const { data } = await http({
                url: target.usePrefix ? http.adornUrl((target._baseUrl || '') + handleUrl) : ((target._baseUrl || '') + handleUrl),
                method: 'POST',
                data: params,
                headers
            })
            return method(data)
        }
    }
}

export function FormPost(url: string = '', flag?: boolean, headers?: any) {
    return function (target, _prop: string, descriptor: PropertyDescriptor) {
        const method = descriptor.value
        descriptor.value = async function () {
            let params = arguments[0]
            const isSimple = ['string', 'number'].includes(typeof params)
            const handleUrl = handlePath(url, params)
            if (isSimple) {
                params = {}
            }
            const { data } = await http({
                url: target.usePrefix ? http.adornUrl((target._baseUrl || '') + handleUrl) : ((target._baseUrl || '') + handleUrl),
                method: 'POST',
                params: http.adornParams(params, flag),
                headers
            })
            return method(data)
        }
    }
}

export function AuthPost(url: string = '', flag?: boolean, headers?: any) {
    const { base } = allConfig
    return function (target, _prop: string, descriptor: PropertyDescriptor) {
        const method = descriptor.value
        descriptor.value = async function () {
            let params = arguments[0]
            const isSimple = ['string', 'number'].includes(typeof params)
            const handleUrl = handlePath(url, params)
            if (isSimple) {
                params = {}
            }
            let authToken = ''
            if (base.auth_api) {
                const result = await http({
                    url: http.adornUrl(base.auth_api)
                })
                authToken = result.data.data
            }

            const { data } = await http({
                url: target.usePrefix ? http.adornUrl((target._baseUrl || '') + handleUrl) : ((target._baseUrl || '') + handleUrl),
                method: 'POST',
                data: http.adornData(params, flag),
                headers: base.auth_token_key ? {
                    [base.auth_token_key]: authToken,
                    ...headers
                } : headers
            })
            return method(data)
        }
    }
}

export function Put(url: string = '', flag?: boolean, headers?: any) {
    return function (target, _prop: string, descriptor: PropertyDescriptor) {
        const method = descriptor.value
        descriptor.value = async function () {
            let params = arguments[0]
            const isSimple = ['string', 'number'].includes(typeof params)
            const handleUrl = handlePath(url, params)
            if (isSimple) {
                params = {}
            }
            const { data } = await http({
                url: target.usePrefix ? http.adornUrl((target._baseUrl || '') + handleUrl) : ((target._baseUrl || '') + handleUrl),
                method: 'PUT',
                data: http.adornData(params, flag),
                headers
            })
            return method(data)
        }
    }
}

export function Delete(url: string = '', flag?: boolean, headers?: any) {
    return function (target, _prop: string, descriptor: PropertyDescriptor) {
        const method = descriptor.value
        descriptor.value = async function () {
            let params = arguments[0]
            const isSimple = ['string', 'number'].includes(typeof params)
            const handleUrl = handlePath(url, params)
            if (isSimple) {
                params = {}
            }
            const { data } = await http({
                url: target.usePrefix ? http.adornUrl((target._baseUrl || '') + handleUrl) : ((target._baseUrl || '') + handleUrl),
                method: 'DELETE',
                data: http.adornData(params, flag),
                headers
            })
            return method(data)
        }
    }
}


export function Request() {
    return function (target, prop, ar) {
        console.log('我是参数Request装饰器', target, prop, ar);
    }
}

export function Response() {
    return function (target, prop, ar) {
        console.log('我是参数Response装饰器', target, prop, ar);
    }
}


export function Route(path: string) {
    return function (target) {
        console.log(target, 'Route', path);
    }
}


/**
 * @email 邮箱校验
 * @phone 手机号校验
 * @numberCharacter 只能输入数字字母
 * @numberCharacter_ 只能输入数字字母下划线
 * @numberGreaterThan0 大于0的数字
 * @numberGreaterThanOrEqualTo0 大于等于0的数字
 * @integerNumberGreaterThan0 大于0的整数
 * @integerNumberGreaterThanOrEqualTo0 大于等于0的整数
 * @retain2Decimals 保留2位小数
 */
type RegRule = 'email' |
    'phone' |
    'numberCharacter' |
    'numberCharacter_' |
    'numberGreaterThan0' |
    'numberGreaterThanOrEqualTo0' |
    'integerNumberGreaterThan0' |
    'integerNumberGreaterThanOrEqualTo0' |
    'retain2Decimals'

/**
 * 正则校验
 * @param tip 自定义提示文字
 * @returns 
 */
export function Rule(rule: RegRule | RegExp, tip?: string) {
    return function (_target, _prop: string, descriptor: PropertyDescriptor) {
        let ruleReg: RegExp
        let autoLabel = ''
        if (rule instanceof RegExp) {
            ruleReg = rule
        } else {
            switch (rule) {
                case 'email':
                    ruleReg = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/
                    break
                case 'phone':
                    ruleReg = /^1[3456789]\d{9}$/
                    break
                case 'numberCharacter':
                    ruleReg = /^[0-9a-zA-Z]+$/
                    break
                case 'numberCharacter_':
                    ruleReg = /^[0-9a-zA-Z_]+$/
                    break
                case 'numberGreaterThan0':
                    ruleReg = /^[1-9]\d*(\.\d+)?$/
                    break
                case 'numberGreaterThanOrEqualTo0':
                    ruleReg = /^[0-9]\d*(\.\d+)?$/
                    break
                case 'integerNumberGreaterThan0':
                    ruleReg = /^[1-9]\d*$/
                    break
                case 'integerNumberGreaterThanOrEqualTo0':
                    ruleReg = /^[0-9]\d*$/
                    break
                case 'retain2Decimals':
                    ruleReg = /^\d+(\.\d{1,2})?$/
                    break
            }
        }

        const validateRule = (_rule: any, value: any, callback: any) => {
            if (!value || ruleReg.test(value)) {
                callback()
            } else {
                callback(new Error(tip ? tip : autoLabel + '格式不正确！'))
            }
        }
        const method = descriptor.value
        descriptor.value = function () {
            const result = method.bind(this)()
            autoLabel = result.label
            let rules: any = []
            if (result.rules) {
                rules = [...result.rules, { validator: validateRule, trigger: 'blur' }]
            } else {
                rules = [{ validator: validateRule, trigger: 'blur' }]
            }
            return {
                ...result,
                rules: rules
            }
        }
    }
}

export function Reactive() {
    return (target) => {
        console.log('target', target);
        Object.getOwnPropertyNames(target).forEach(name => {
            console.log(name);

        })
    }
}